﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate.Linq;
using NHibernate;
using System.Linq.Expressions;

namespace Persistence.IDao
{
    public abstract class DaoBase<T> : Spring.Data.NHibernate.Generic.Support.HibernateDaoSupport, IDao<T> where T : class
    {
        public T Get(object id)
        {
            return HibernateTemplate.Get<T>(id);
        }

        public T Load(object id)
        {
            throw new NotImplementedException();
        }

        public object Save(T entity)
        {
            return HibernateTemplate.Save(entity);
        }

        public void Update(T entity)
        {
            HibernateTemplate.Update(entity);
        }

        public void SaveOrUpdate(T entity)
        {
            HibernateTemplate.SaveOrUpdate(entity);
        }

        public object SaveOrUpdateCopy(T entity)
        {
            return HibernateTemplate.SaveOrUpdateCopy(entity);
        }

        public object Merge(T entity)
        {
            return HibernateTemplate.Merge(entity);
        }

        public void Delete(object id)
        {
            var entity = HibernateTemplate.Get<T>(id);
            if (entity == null)
            {
                return;
            }

            HibernateTemplate.Delete(entity);
        }

        public void DeleteList(IList<object> idList)
        {
            foreach (object item in idList)
            {
                var entity = HibernateTemplate.Get<T>(item);
                if (entity == null)
                {
                    return;
                }

                HibernateTemplate.Delete(entity);
            }
        }

        public IQueryable<T> LoadAll()
        {
            IQueryable<T> result = Session.Query<T>();
            return result;
        }

        public IQueryable<T> LoadAllWithPage(out long count, int pageIndex, int pageSize)
        {
            IQueryable<T> result = Session.Query<T>();
            count = result.LongCount();

            return result.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public IQueryable<T> LoadAllWithPageOrderBy(out long count, int pageIndex, int pageSize, string propertyName, bool IsDesc = false)
        {
            IQueryable<T> result = Session.Query<T>();
            count = result.LongCount();

            var param = Expression.Parameter(typeof(T));
            var body = Expression.Property(param, propertyName);
            dynamic keySelector = Expression.Lambda(body, param);

            IQueryable<T> resultOrderBy = null;
            if (IsDesc)
            {
                resultOrderBy = Queryable.OrderByDescending(result, keySelector);
            }
            else
            {
                resultOrderBy = Queryable.OrderBy(result, keySelector);
            }

            return resultOrderBy.Skip((pageIndex - 1) * pageSize).Take(pageSize);
        }

        public void Save(IList<T> objects)
        {
            using (IStatelessSession session = SessionFactory.OpenStatelessSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    foreach (T o in objects)
                    {
                        session.Insert(o);
                    }
                    transaction.Commit();
                }
            }
        }

        public void Update(IList<T> objects)
        {
            using (IStatelessSession session = SessionFactory.OpenStatelessSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    foreach (T o in objects)
                    {
                        session.Update(o);
                    }
                    transaction.Commit();
                }
            }
        }

        public void Delete(IList<T> objects)
        {
            using (IStatelessSession session = SessionFactory.OpenStatelessSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    foreach (T o in objects)
                    {
                        session.Delete(o);
                    }
                    transaction.Commit();
                }
            }
        }
    }
}